package com.test.context;

import com.test.aware.ApplicationContextAwareProcessor;
import com.test.environment.ConfigurableEnvironment;
import com.test.environment.StandardEnvironment;
import com.test.event.*;
import com.test.exception.BeansException;
import com.test.factory.ConfigurableListableBeanFactory;
import com.test.listener.ApplicationListener;
import com.test.processor.BeanFactoryPostProcessor;
import com.test.processor.BeanPostProcessor;
import com.test.resource.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * AbstractApplicationContext类是Spring IoC容器的一个基础实现，
 * 提供了应用程序上下文的通用功能，包括Bean的初始化、事件处理、环境配置等。
 * 该类继承了DefaultResourceLoader并实现了ConfigurableApplicationContext接口。
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

    // 应用程序名称
    private String applicationName = "";

    // 启动日期
    private long startupDate;

    // 应用程序事件多播器
    private ApplicationEventMulticaster applicationEventMulticaster;

    // 环境配置
    private ConfigurableEnvironment environment;

    // 构造函数
    public AbstractApplicationContext() {
    }

    /**
     * 刷新应用程序上下文，包括初始化Bean工厂、处理Bean以及广播事件等。
     * 此方法是整个应用程序上下文启动的核心方法。
     */
    public void refresh() throws Exception {
        prepareRefresh();

        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        prepareBeanFactory(beanFactory);

        try {
            postProcessBeanFactory(beanFactory);

            invokeBeanFactoryPostProcessors(beanFactory);

            registerBeanPostProcessors(beanFactory);

            initApplicationEventMulticaster();

            onRefresh();

            registerListeners();

            finishBeanFactoryInitialization(beanFactory);

            finishRefresh();
        } catch (BeansException ex){
            destroyBeans();

            cancelRefresh(ex);

            throw ex;
        }
    }

    /**
     * 准备刷新上下文的操作，包括设置启动日期和初始化属性源。
     */
    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();

        initPropertySources();

        getEnvironment();
    }

    /**
     * 初始化属性源的模板方法，由子类实现具体逻辑。
     */
    protected void initPropertySources() {
        //默认实现为空，子类可以覆盖
    }

    /**
     * 抽象方法，获取一个新Bean工厂的实例。
     *
     * @return ConfigurableListableBeanFactory实例
     */
    protected abstract ConfigurableListableBeanFactory obtainFreshBeanFactory() throws Exception;

    /**
     * 准备Bean工厂，包括添加Bean后处理器。
     *
     * @param beanFactory Bean工厂实例
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
    }

    /**
     * 处理Bean工厂的钩子方法，子类可以覆盖。
     *
     * @param beanFactory Bean工厂实例
     */
    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        //默认实现为空，子类可以覆盖
    }

    /**
     * 调用Bean工厂后处理器，允许它们修改Bean工厂的配置。
     * @param beanFactory Bean工厂实例
     */
    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanFactoryPostProcessor> postProcessorMap = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        for (BeanFactoryPostProcessor postProcessor : postProcessorMap.values()) {
            postProcessor.postProcessBeanFactory(beanFactory);
        }
    }

    /**
     * 注册Bean后处理器，以便在Bean初始化前后进行处理。
     *
     * @param beanFactory Bean工厂实例
     */
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        Map<String, BeanPostProcessor> postProcessorMap = beanFactory.getBeansOfType(BeanPostProcessor.class);
        for (BeanPostProcessor postProcessor : postProcessorMap.values()) {
            beanFactory.addBeanPostProcessor(postProcessor);
        }
    }

    /**
     * 初始化应用程序事件多播器。
     */
    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    }

    /**
     * 在刷新过程中执行特定于子类的操作。
     */
    protected void onRefresh() {
        //默认实现为空，子类可以覆盖
    }

    /**
     * 注册应用程序事件监听器。
     */
    protected void registerListeners() {
        Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
        for (ApplicationListener listener : applicationListeners) {
            applicationEventMulticaster.addApplicationListener(listener);
        }
    }

    /**
     * 完成Bean工厂的初始化，包括预实例化单例Bean。
     *
     * @param beanFactory Bean工厂实例
     */
    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.preInstantiateSingletons();
    }

    /**
     * 完成刷新操作，包括设置启动日期和发布上下文刷新事件。
     */
    protected void finishRefresh() {
        this.startupDate = System.currentTimeMillis();

        publishEvent(new ContextRefreshedEvent(this));
    }

    /**
     * 销毁所有Beans。
     */
    protected void destroyBeans() {
        getBeanFactory().destroySingletons();
    }

    /**
     * 取消刷新操作，子类可以覆盖此方法。
     *
     * @param ex 异常实例
     */
    protected void cancelRefresh(BeansException ex) {
        //默认实现为空，子类可以覆盖
    }

    /**
     * 发布应用程序事件。
     *
     * @param event 应用程序事件实例
     */
    public void publishEvent(ApplicationEvent event) {
        applicationEventMulticaster.multicastEvent(event);
    }

    /**
     * 关闭应用程序上下文，包括发布关闭事件和销毁Beans。
     */
    public void close() {

        publishEvent(new ContextClosedEvent(this));
        destroyBeans();
    }

    /**
     * 抽象方法，获取Bean工厂实例。
     *
     * @return ConfigurableListableBeanFactory实例
     * @throws IllegalStateException 如果上下文未刷新
     */
    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

    /**
     * 设置应用程序名称。
     *
     * @return 应用程序名称
     */
    public String setApplicationName() {
        return this.applicationName;
    }

    /**
     * 获取启动日期。
     *
     * @return 启动日期
     */
    public long getStartupDate() {
        return this.startupDate;
    }

    /**
     * 从Bean工厂中获取Bean实例。
     *
     * @param name Bean名称
     * @return Bean实例
     */
    public Object getBean(String name){
        return getBeanFactory().getBean(name);
    }

    /**
     * 从Bean工厂中获取指定类型的Bean实例。
     *
     * @param name Bean名称
     * @param requiredType 所需类型
     * @param <T> 类型参数
     * @return Bean实例
     * @throws BeansException 如果获取Bean失败
     */
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(name, requiredType);
    }

    /**
     * 从Bean工厂中获取指定类型的Bean实例。
     *
     * @param requiredType 所需类型
     * @param <T> 类型参数
     * @return Bean实例
     * @throws BeansException 如果获取Bean失败
     */
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        return getBeanFactory().getBean(requiredType);
    }

    /**
     * 从Bean工厂中获取Bean实例。
     *
     * @param name Bean名称
     * @param args 构造参数
     * @return Bean实例
     * @throws BeansException 如果获取Bean失败
     */
    public Object getBean(String name, Object... args) throws BeansException {
        return getBeanFactory().getBean(name, args);
    }

    /**
     * 检查Bean工厂中是否包含指定名称的Bean。
     *
     * @param name Bean名称
     * @return 如果包含则返回true，否则返回false
     */
    public boolean containsBean(String name) {
        return getBeanFactory().containsBean(name);
    }

    /**
     * 获取指定类型的Beans集合。
     *
     * @param type 类型
     * @param <T> 类型参数
     * @return Beans集合
     * @throws BeansException 如果获取Beans失败
     */
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        return getBeanFactory().getBeansOfType(type);
    }

    /**
     * 获取Bean定义名称数组。
     *
     * @return Bean定义名称数组
     */
    public String[] getBeanDefinitionNames() {
        return getBeanFactory().getBeanDefinitionNames();
    }

    /**
     * 获取环境配置。
     *
     * @return ConfigurableEnvironment实例
     */
    public ConfigurableEnvironment getEnvironment() {
        if (this.environment == null) {
            this.environment = createEnvironment();
        }
        return this.environment;
    }

    /**
     * 创建环境配置实例。
     *
     * @return ConfigurableEnvironment实例
     */
    protected ConfigurableEnvironment createEnvironment() {
        return new StandardEnvironment();
    }

    /**
     * 设置环境配置。
     *
     * @param environment 环境配置实例
     */
    public void setEnvironment(ConfigurableEnvironment environment) {
        this.environment = environment;
    }
}
